#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio_keys.h>
#include <linux/of_irq.h>
#include <linux/gpio.h>
#include <linux/property.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>

#define DRIVER_NAME "imx6ul,dts-tree"


static int devtree_probe(struct platform_device * pdev)
{
    struct fwnode_handle *child;
    const char *p1,*p2[3];
    u32 p3[2],value;
    u8 testmac[6];
    int i=0;

    printk(KERN_INFO "\n**********devtree_probe******************\n");

    device_property_read_string(&pdev->dev,"test-string",&p1);
    printk("devtree_probe node  test-string is: %s\n",p1);

    device_property_read_string_array(&pdev->dev, "test-strings", p2, 3);
    printk("devtree_probe node test-strings is: %s%s%s\n",p2[0],p2[1],p2[2]);

    device_property_read_u32(&pdev->dev,"test-u32",&value);
    printk("devtree_probe node test-u32 is: <%d>\n",value);

    device_property_read_u32_array(&pdev->dev, "test-u32s", p3, 2);
    printk("devtree_probe node test-u32s is: <%d>,<%d>\n",p3[0],p3[1]);

    device_property_read_string(&pdev->dev,"compatible",&p1);
    printk("devtree_probe node  compatible is: %s\n",p1);

    device_property_read_string(&pdev->dev,"status",&p1);
    printk("devtree_probe node  status is: %s\n",p1);

    printk(" \n * devtree_probe child node \n");

    device_for_each_child_node(&pdev->dev, child){

        printk("*************childnode%d*************\n",i++);      
        fwnode_property_read_string(child,"test-string",&p1);
        printk("childnode test-string is: %s\n",p1);

        fwnode_property_read_string_array(child,"test-strings",p2,3);
        printk("childnode  test-strings is: %s%s%s\n",p2[0],p2[1],p2[2]);

        fwnode_property_read_u32_array(child,"test-u32",&value,1);
        printk("childnode test-u32 is: <%d>\n",value);

        fwnode_property_read_u32_array(child,"test-u32s",p3,2);
        printk("childnode  test-u32s is: <%d>,<%d>\n",p3[0],p3[1]);

        fwnode_property_read_u8_array(child,"test-u8s",testmac,6);
        printk("childnode test-u32s is: [%x,%x,%x,%x,%x,%x]\n",testmac[0],testmac[1],testmac[2],testmac[3],testmac[4],testmac[5]);  

    }

    return 0;
}
static int devtree_remove(struct platform_device * pdev)
{
    printk(KERN_INFO "devtree_remove\n");

    return 0;
}

static const struct of_device_id of_devtree_dt_match[] = {
    {.compatible = DRIVER_NAME},
    {},
};

MODULE_DEVICE_TABLE(of,of_devtree_dt_match);

static struct platform_driver devtree_test_driver = {
    .probe  = devtree_probe,
    .remove = devtree_remove,
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .of_match_table = of_devtree_dt_match,
        },
};


static int devtree_test_init(void)
{
    int num=0,i=0,value;
    const char *p1;
    struct device_node *node1,*childnode1;
    u32 p2[2];
    u8 testmac[6];

    printk(KERN_INFO "devtree_test_init\n");
    printk("\n*************devtree init start ***************\n");

    node1 = of_find_node_by_path("/dts_test");
    if(node1 == NULL){
        printk("of_find_node_by_path failed\n");
        return -ENODEV;
    }
    else{
        printk("of_find_node_by_path dts_test ok\n");
    }
    //read string
    of_property_read_string(node1, "test-string", &p1);
    printk("dts_test node :test-string is: %s\n",p1);
    //read strings
    num = of_property_count_strings(node1, "test-strings");
    printk("dts_test node  test-strings num is: %d\n",num);
    for(i=0;i<num;i++){
        of_property_read_string_index(node1,"test-strings",i,&p1);
        printk("%s",p1);
    }
    //read string "compatible"
    of_property_read_string(node1, "compatible", &p1);
    printk("dts_test node  compatible is: %s\n",p1);

    //read string "status"
    of_property_read_string(node1, "status", &p1);
    printk("dts_test node   status is: %s\n",p1);

    //read u32 "test-u32"
    of_property_read_u32(node1,"test-u32",&value);
    printk("dts_test node  test-u32 is: <%d>\n",value);

    //read  u32s test-u32s 
    of_property_read_u32_array(node1, "test-u32s", p2, 2);
    printk("dts_test node  test-u32s is: <%d>,<%d>\n",p2[0],p2[1]);

    //read u8s test-u8s
    of_property_read_u8_array(node1, "test-u8s", testmac, 6);
    printk("dts_test node test-u8s is: <%x>,<%x>,<%x>,<%x>,<%x>,<%x>\n",testmac[0],testmac[1],testmac[2],testmac[3],testmac[4],testmac[5]);

    //get "dts_child_node1" device node  
    childnode1 = of_get_child_by_name(node1,"dts_child_node1");
    if(childnode1 == NULL){
        printk("of_get_child_by_name failed\n");
        return -ENODEV;
    }
    printk("of_get_child_by_name dts_child_node1 ok\n");
    of_property_read_string(childnode1, "test-string", &p1);
    printk("dts_child_node1 node test-string is: %s\n",p1);


    return platform_driver_register(&devtree_test_driver);
}

static void devtree_test_exit(void)
{
    printk(KERN_INFO "\ndevtree_test_exit\n");
    platform_driver_unregister(&devtree_test_driver);
}

module_init(devtree_test_init);
module_exit(devtree_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zheng");